home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 21 / Mac Magazin and MacEasy Magazine CD - Issue 21.iso / Wissenschaft & Technik / yorick_docs folder / yorick_docs / NOTES < prev    next >
Text File  |  1996-02-28  |  19KB  |  427 lines

  1.                    
  2.                  Notes on the
  3.                 Yorick
  4.             Interpretive Language
  5.  
  6. ------------------------------------------------------------------------
  7.  
  8. 1. General description
  9. ----------------------
  10.  
  11. Yorick syntax is designed to imitate C syntax.  This enables text
  12. editors which understand C syntax, such as GNU Emacs, to work without
  13. modification on Yorick code.
  14.  
  15. However, Yorick handles variables more like LISP than C.  This is
  16. primarily a consequence of the fact that LISP, like Yorick, is
  17. designed as an interpreter.  A variable "remembers" its data type, so
  18. there is no need for type declarations in Yorick.  They are replaced
  19. by the type conversion and array building functions.  Variable scoping
  20. rules in Yorick strongly resemble LISP scoping rules.  Each variable
  21. is either local or external with respect to the current function; an
  22. external variable will inherit the value of the most recent calling
  23. function for which it is local.
  24.  
  25. Finally, Yorick array index and function call syntax resembles
  26. FORTRAN.  Like FORTRAN (but unlike C), Yorick places little emphasis
  27. on the storage order of arrays; emphasizing instead the independence
  28. of the several dimensions of a multidimensional array.  Yorick
  29. function calls are indistinguishable from indexed arrays -- and not
  30. simply syntactically indistinguishable as in FORTRAN, since a single
  31. Yorick expression of the form "x(i,j)" would result in a function call
  32. if x happened to be a function, but could later represent an indexed
  33. array if the data type of "x" changed from function to array.
  34.  
  35. Unlike C and FORTRAN, Yorick is an interpreter.  What you type will
  36. execute immediately without any further ado.  Yorick recoups much of
  37. the penalty in execution speed associated with interpreters by
  38. providing a powerful vector syntax.  You need very few loops in
  39. Yorick, since an expression involving an array "x" automatically
  40. applies to each element of "x" to produce an array result.  An
  41. important side effect is that you need not pass array dimensions as
  42. arguments to procedures; every variable "remembers" its dimensions
  43. just as it "remembers" its data type.
  44.  
  45. Yorick provides for both ASCII and binary input and output.  Most of
  46. the functionality of the ANSI standard C library for ASCII I/O and
  47. string manipulation is available for use by interpreted routines.  The
  48. binary I/O requires only that you be able to specify the layout of the
  49. file in the manner of a C struct statement; after you have done this,
  50. Yorick transparently moves data arrays from disk to memory and
  51. vice-versa.  Like Stewart Brown's PDB library, Yorick supports
  52. automatic binary data type conversions to allow files written on one
  53. type of machine to be read on another, or to allow a program on one
  54. machine to write a file containing numbers in the format native to a
  55. different machine.
  56.  
  57. Finally, Yorick is extensible.  Special versions of Yorick may be
  58. created which include compiled code to do special purpose number
  59. crunching.  The compiled code takes its inputs from arrays generated
  60. by the Yorick interpreter, and passes its results back to arrays which
  61. will be visible to interpreted code.
  62.  
  63.  
  64. 2. Language
  65. -----------
  66.  
  67. A Yorick program consists of either a single executable statement --
  68. the "*main*" program -- or a function definition, or a data structure
  69. definition.
  70.  
  71. 2A. Executable statements
  72.  
  73. An executable statement is typically an assignment statement:
  74.  
  75.      x= 3;
  76.      temp_variable = array(int, 3,4);
  77.      quad_sol= (-b + sqrt(b^2 - 4*a*c))/(2*a)
  78.  
  79. The trailing semicolon is optional -- if no semicolon is present, and
  80. expression would be complete and legal at the end of a line, Yorick
  81. supplies a semicolon.  If the final character of a line is a backslash
  82. (\), Yorick will not automatically supply a semicolon.  The intent is
  83. to allow you to omit typing trailing semicolons on lines entered from
  84. the keyboard.  I strongly recommend you include the terminating
  85. semicolons explicitly in Yorick source code files, to enhance the
  86. resemblance with C.
  87.  
  88. A second common executable statement is a subroutine call:
  89.  
  90.      read, a, b, c;
  91.      print, (-b+sqrt(b^2-4*a*c))/(2*a), (-b-sqrt(b^2-4*a*c))/(2*a);
  92.      do_something
  93.  
  94. Notice that if the subroutine has arguments, its name is separated
  95. from them by a comma.  This rule is necessitated by a third form of
  96. executable statement in Yorick: the implied print statement.  Any
  97. statement which consists solely of an expression will print the value
  98. of that expression.  Hence, instead of the above explicit call to the
  99. print function, you could have written:
  100.  
  101.      (-b+sqrt(b^2-4*a*c))/(2*a); (-b-sqrt(b^2-4*a*c))/(2*a)
  102.  
  103. (The only difference is that a print with two arguments will print the
  104. results on the same line, while each individual expression which is
  105. printed via an implied print statement appears on a separate line.)
  106. Note also that explicit use of the semicolon delimiter allows you to
  107. stack several statements on a single input line.
  108.  
  109. The following statement is ambiguous:
  110.  
  111.      x;
  112.  
  113. If x is a function, this calls the function x with no arguments, then
  114. discards any result.  If x is not a function, it is printed as an
  115. implied print statement.  Yorick resolves this ambiguity at run time,
  116. just as it resolves the ambiguity between a function call x(i,j) and
  117. an indexed array x(i,j) at run time.
  118.  
  119. The remaining executable statements in Yorick are control structures.
  120. Yorick supports C-style if/else conditionals and while/do/for loops.
  121. Yorick does not support the C switch statement.  (The only way I could
  122. think of to implement switch would have been equivalent to an if/else
  123. chain).  Yorick provides the C break and continue statements to break
  124. out of and abort a pass through a loop, respectively.  Yorick supports
  125. the infamous C goto statement, which, as in C should be used only to
  126. break out of deeply nested loops, and possibly to branch to error
  127. processing code.  In a word, use goto sparingly at most.  The syntax
  128. for these is:
  129.  
  130.      if (condition_expression) if_statement
  131.      if (condition_expression) if_statement else else_statement
  132.      while (condition_expression) body
  133.      do body while (condition_expression)
  134.      for (init_expression ; condition_expression ; inc_expression) body
  135.  
  136. The "if_statement", "else_statement", or "body" may be either a single
  137. executable statement, or a compound statement.  A compound statement
  138. consists of several single statements enclosed in curly braces, as in:
  139.  
  140.      for (i=1 ; i<=n ; i++) {
  141.        if (get_abc_data(i)) {
  142.          print, "data at point"+swrite(i)+" unavailable";
  143.          continue;  /* abort this pass of the enclosing for loop */
  144.        }
  145.        root1= root2= 0.0;
  146.        if (!a) {
  147.          if (!b) break;  /* exit the enclosing for loop now */
  148.          root1= root2= -c/b;
  149.        } else if (b^2 > 4*a*c) {
  150.          root1= (-b+sqrt(b^2-4*a*c))/(2*a);
  151.          root2= (-b-sqrt(b^2-4*a*c))/(2*a);
  152.        } else {
  153.          print, "negative discriminant at point "+print(i)(0);
  154.          break;          /* exit the enclosing for loop now */
  155.        }
  156.        print, root1, root2;
  157.      }
  158.  
  159. In addition to the use of compound statements, the for loop, and the
  160. if/else constructs, note these features of the above code fragment:
  161. (1) The = operator is a binary operator like + or *, with the side
  162.     effect of redefining the left hand operand.  Its value is the
  163.     value which was assigned, so that
  164.       root1= root2= 0.0;
  165.     first redefines root2 to be 0.0.  This operation has a value of
  166.     0.0, and root1 is then redefined to this value.
  167. (2) The + operator concatenates strings.
  168. (3) The swrite function converts array data into ASCII.  If print
  169.     is invoked as a function, it will also return a string array
  170.     instead of printing the result at the terminal.
  171. (4) Yorick comments begin with /* and end with */, like C comments.
  172.     Yorick also recognizes comments introduced with // and ending with
  173.     newline (C++ style), or introduced with # and ending with newline
  174.     (Unix shell style).
  175.     Yorick will also ignore all lines between a line consisting of
  176.     "#if 0" and a matching line "#endif", but no other C preprocessor
  177.     directives, such as "#define" or "#ifdef", are recognized.  (The
  178.     philosophy of Yorick is that they should be unnecessary.)
  179.  
  180. 2B. Function definitions
  181.  
  182. A group of Yorick statements may be collected into a Yorick function,
  183. which can then be invoked either as a subroutine or as a function.
  184. All Yorick functions return some value, although a special value
  185. nil, [], is available to represent lack of data.  The return value is
  186. discarded if the function is invoked as a subroutine.  Because of
  187. the LISP-like variable scoping, Yorick functions can and should be
  188. used as macros: any variable not defined locally within the function
  189. will be retrieved from the context in which the function was called.
  190. Yorick functions do have local variables, and consequently can be
  191. used in the style of C functions as well.
  192.  
  193. A Yorick function definition looks like this:
  194.  
  195.      func quad_solve(a, b, c)
  196.      /* return the roots x of the quadratic equation
  197.         a*x^2 + b*x + c = 0  */
  198.      {
  199.        discrim= b^2 - 4*a*c;
  200.        q= -0.5*(b+sign(b)*sqrt(discrim));
  201.        return [q/a, c/q];
  202.      }
  203.  
  204. The square bracket operator [...] builds an array by concatenating its
  205. arguments.  In this case, for example,
  206.  
  207.      quad_solve(1,0,-1)
  208.  
  209. prints "[-1,1]", which are the two solutions of x^2-1=0.  Or, we could
  210. save the result in the variable x with:
  211.  
  212.      x= quad_solve(1,0,-1)
  213.  
  214. Then x(1) would be -1 and x(2) would be 1.  (Yorick array indices are
  215. 1-origin by default -- more on this later.)
  216.  
  217. Notice that Yorick silently converts the data types of the inputs
  218. (1,0,-1) from integer to floating point.  The real power of the Yorick
  219. interpreter, however, comes from the fact that the input arguments to
  220. quad_solve can themselves be arrays.  All of the operators =, ^, +, -,
  221. *, /, and even [...] will be applied to every element of the input
  222. arrays.
  223.  
  224. Yorick's array operations rely on the notion of conformability between
  225. operands in binary operations.  Conformability in Yorick follows a
  226. simple, universal rule: Two Yorick arrays are conformable if the
  227. lengths of their corresponding dimensions match exactly, or, failing
  228. an exact match, if one or the other dimension has length 1.  If one
  229. array has more dimensions than the other, the "missing" dimensions of
  230. the shorter array are treating as dimensions of length 1.  A binary
  231. operation between two conformable arrays returns a result which has
  232. the longer of the dimensions of its operands.  (Note that adding a
  233. 1-by-15 array to a 20-by-1 array produces a 20-by-15 result by this
  234. rule.)  The result is obtained by performing the binary operation on
  235. the corresponding elements of the left an right operands -- the single
  236. index of a 1-length dimension combining with every index value in turn
  237. of the corresponding index of the other operand.  Note that scalar
  238. multiplication is a special case of this general rule.
  239.  
  240. Hence,
  241.  
  242.      quad_solve(1,0,-[1,4,9,16])
  243.  
  244. prints "[[-1,-2,-3,-4],[1,2,3,4]]" -- a two dimensional result, while
  245.  
  246.      quad_solve([1,4](-,),0,-[1,4,9,16])
  247.  
  248. prints "[[[-1,-2,-3,-4],[-0.5,-1,-1.5,-2]],[[1,2,3,4],[0.5,1,1.5,2]]]"
  249. -- a three dimensional result.  The indices represent, in order, (1)
  250. the solutions for c= 1, 4, 9, and 16, (2) the solutions for a= 1 and
  251. 4, and (3) the two roots of the equation.  The special array index
  252. "-", used in the above example "[1,4](-,)", inserts a 1-length
  253. dimension into an array.  Thus, "[1,4]" is a 1D array with length 2,
  254. and "[1,4](-,)" is a 1-by-2 2D array.  Without the "(-,)", the call to
  255. quad_solve will cause a run time error:
  256.  
  257.      quad_solve([1,4],0,-[1,4,9,16])
  258.      ERROR (quad_solve) operands not conformable in binary *
  259.  
  260. since the operation a*c in the first line of quad_solve would be [1,4]
  261. * (-[1,4,9,16]), an the length 2 vector is not conformable with the
  262. length 4 vector.  However, [1,4](-,) * (-[1,4,9,16]) is a legal
  263. operation, producing the 2D result [[-1,-4,-9,-16],[-4,-16,-36,-64]].
  264.  
  265. The combination of the Yorick conformability rule and the "-" array
  266. pseudo-index is very convenient for dealing with the multidimensional
  267. arrays common in physical modeling.
  268.  
  269. Yorick also supports functions with a variable number of arguments,
  270. and functions with keyword arguments.  Ordinary positional parameters
  271. and keyword parameters may be used to output results; that is, if
  272. these parameters were supplied as a simple variable reference, then
  273. that variable will be redefined to the local value of the function
  274. parameter when the function returns.  Thus, function parameters in
  275. Yorick have the "look and feel" of FORTRAN call-by-reference function
  276. parameters.  (In reality, of course, every Yorick variable is a
  277. reference to a reference several levels deep -- Yorick must keep track
  278. of a lot of descriptive information in addition to the mere value of a
  279. variable.)
  280.  
  281. 2C. Structure definitions
  282.  
  283. A Yorick structure definition resembles a C structure definition,
  284. except that dimension lists are Yorick/FORTRAN style, and complicated
  285. C data types are not allowed.  Roughly speaking, any C data type
  286. which requires parentheses (or the use of a typedef which requires
  287. parentheses) will not be legal in Yorick.  The basic data types
  288. recognized by Yorick are:
  289.  
  290.      char
  291.      short
  292.      int
  293.      long
  294.      float
  295.      double
  296.      complex
  297.      string
  298.      pointer
  299.  
  300. The first six have identical meaning with the data type of the same
  301. name in C (except that Yorick's "char" may mean C's "unsigned char").
  302. The last three correspond to the following C typedefs:
  303.  
  304.     typedef struct { double re, im; } complex; /* in C, not Yorick */
  305.     typedef char *string;                      /* in C, not Yorick */
  306.     typedef void *pointer;                     /* in C, not Yorick */
  307.  
  308. Yorick's strings are either NULL (0) pointers, or 0-terminated strings
  309. of characters, normally used to represent text.  Yorick's pointer data
  310. type may either be NULL (0), or point to a Yorick array (of any data
  311. type/structure) -- Yorick can NOT handle a fully general pointer to
  312. anywhere in memory in the spirit of a C pointer.  Nevertheless, the
  313. VALUE of a Yorick pointer corresponds exactly to the VALUE of a
  314. pointer (of the appropriate type) referencing the same data in C.
  315. Hence, a Yorick pointer may be passed into a compiled C routine either
  316. directly, or as a member of a larger data structure without any
  317. behind-the-scenes tinkering.  Unlike C, however, Yorick knows not only
  318. the type of the object referenced by a pointer, but also its
  319. dimensionality.  Hence, when you dereference a Yorick pointer, you get
  320. an ordinary Yorick array, complete with its dimension information, not
  321. just a scalar.  Yorick also keeps track of the number of references to
  322. its arrays, so memory is automatically freed when the last Yorick
  323. pointer referencing it disappears.
  324.  
  325. Yorick arrays may also have compound types consisting of named members
  326. which are arrays of the basic types, or arrays of previously defined
  327. compound types.
  328.  
  329.      struct Mesh {
  330.        long imax, jmax;
  331.        double *x, *y;
  332.        int *region;
  333.      }
  334.  
  335.      x= Mesh(imax=31, jmax=11, x= &xarray, y= &yarray, region= &rarray);
  336.  
  337. 2C. Comments
  338.  
  339. Yorick comments begin with /* and end with */, as in C.  A comment may
  340. span any number of lines or be only a small part of a single line.  As
  341. far as the parser is concerned, a comment is equivalent to a single
  342. whitespace.
  343.  
  344. Since this style of comment does not nest, Yorick also recognizes C++
  345. style comments, introduced by // and terminated by a newline, and Unix
  346. shell style comments, introduced by # and terminated by a newline.
  347. Use one of these forms to comment out blocks of lines.
  348.  
  349. 2D. Including files containing Yorick source code
  350.  
  351. To have Yorick switch its input stream to an alternate file, foo.i,
  352. type the following line:
  353.  
  354.      #include "foo.i"
  355.  
  356. Such an include directive may also appear as a line in foo.i itself.
  357. Unlike C, Yorick #include directives must be outside of any func,
  358. struct, or other control structures.  Like C, Yorick accepts <foo.i>
  359. as well as "foo.i".  Nothing else may be "stacked" on an #include
  360. line; it is NOT a Yorick statement.
  361.  
  362. The ".i" suffix for Yorick include files is simply a convention;
  363. Yorick does not care about the name of the include file.  However, I
  364. urge you to stick to this convention; otherwise you won't be able to
  365. tell which files in a directory are Yorick source, and other programs
  366. such as text editors are unlikely to be able to be trained to
  367. recognize your Yorick source files.
  368.  
  369. If you must include files dynamically at runtime, Yorick also provides
  370. two functions -- include and require -- which parse and execute input
  371. files containing Yorick source code at runtime.
  372.  
  373. To locate the file "foo.i" (assuming that "foo.i" is a relative
  374. pathname -- if it is an absolute pathname there is no question),
  375. Yorick follows a standard "include path":
  376.      (1) Is foo.i in the current working directory?
  377.      (2) Is foo.i in the ~/Yorick directory?
  378.      (3) Is foo.i in the Y_SITE/include directory?
  379.      (4) Is foo.i in the Y_SITE/contrib directory?
  380. (Here, Y_SITE is a site-wide Yorick home directory, set when Yorick is
  381. compiled.)  The std.i file in Y_SITE is automatically included at
  382. startup.  You can also place a custom.i file in your ~/Yorick file,
  383. which will be automatically included at startup.  Be sure to copy the
  384. default Y_SITE/include/custom.i into your ~/Yorick directory and read
  385. the instructions therein if you want your own custom.i.
  386.  
  387.  
  388. 3. Getting help
  389. ---------------
  390.  
  391. The basic Yorick functions are defined in the std.i file.  These
  392. include things like dimsof, typeof, structof, and the like, which you
  393. can use to find out about variables.  Also, the print function prints
  394. useful information about functions, structure definitions, I/O
  395. streams, and other non-array objects.  Finally, there is a function
  396. "help", which will describe itself if you type "help".
  397.  
  398.  
  399. 4. How it works
  400. ---------------
  401.  
  402. You can use the disassemble function to find out exactly how Yorick
  403. performs a function.  Yorick parses its input into a series of virtual
  404. machine instructions.  There is a program counter (the first column)
  405. and a stack pointer (depth indicated in the second column).  Runtime
  406. error messages include the value of the program counter when Yorick
  407. blew up.
  408.  
  409. > func sech(x) { y= tanh(x);  return sqrt(1.0-y*y); }
  410. > disassemble, sech
  411. func sech(x)
  412.    3 sp+>1    PushVariable(tanh)
  413.    5 sp+>2    PushReference(x)
  414.    7 sp->1    Eval(1)
  415.    9 sp0>1    Define(y)
  416.   11 sp->0    DropTop
  417.   12 sp+>1    PushVariable(sqrt)
  418.   14 sp+>2    PushDouble(1)
  419.   16 sp+>3    PushVariable(y)
  420.   18 sp+>4    PushVariable(y)
  421.   20 sp->3    Multiply
  422.   21 sp->2    Subtract
  423.   22 sp->1    Eval(1)
  424.   24 sp->0    Return
  425.   25 sp==0    Halt-Virtual-Machine
  426. >
  427.